package com.example.service;

import com.example.model.Announcement;
import com.example.repository.AnnouncementRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 公告服务类
 */
@Slf4j
@Service
public class AnnouncementService {

    @Autowired
    private AnnouncementRepository announcementRepository;

    @Autowired
    private WebSocketService webSocketService;

    /**
     * 创建公告
     */
    @Transactional
    public Announcement createAnnouncement(Announcement announcement) {
        announcement.setCreatedAt(LocalDateTime.now());
        announcement.setUpdatedAt(LocalDateTime.now());
        
        Announcement savedAnnouncement = announcementRepository.save(announcement);
        log.info("创建公告: id={}, title={}, type={}", 
                savedAnnouncement.getId(), savedAnnouncement.getTitle(), savedAnnouncement.getType());
        
        return savedAnnouncement;
    }

    /**
     * 更新公告
     */
    @Transactional
    public Announcement updateAnnouncement(Long id, Announcement announcement) {
        Optional<Announcement> existingOpt = announcementRepository.findById(id);
        if (existingOpt.isEmpty()) {
            throw new RuntimeException("公告不存在: id=" + id);
        }

        Announcement existing = existingOpt.get();
        existing.setTitle(announcement.getTitle());
        existing.setContent(announcement.getContent());
        existing.setType(announcement.getType());
        existing.setTargetType(announcement.getTargetType());
        existing.setPriority(announcement.getPriority());
        existing.setIsPinned(announcement.getIsPinned());
        existing.setScheduledAt(announcement.getScheduledAt());
        existing.setExpiresAt(announcement.getExpiresAt());
        existing.setAttachmentUrl(announcement.getAttachmentUrl());
        existing.setUpdatedAt(LocalDateTime.now());

        Announcement updatedAnnouncement = announcementRepository.save(existing);
        log.info("更新公告: id={}, title={}", updatedAnnouncement.getId(), updatedAnnouncement.getTitle());
        
        return updatedAnnouncement;
    }

    /**
     * 发布公告
     */
    @Transactional
    public void publishAnnouncement(Long id) {
        Optional<Announcement> announcementOpt = announcementRepository.findById(id);
        if (announcementOpt.isEmpty()) {
            throw new RuntimeException("公告不存在: id=" + id);
        }

        Announcement announcement = announcementOpt.get();
        announcement.setStatus(Announcement.PublishStatus.PUBLISHED);
        announcement.setPublishedAt(LocalDateTime.now());
        announcement.setUpdatedAt(LocalDateTime.now());

        announcementRepository.save(announcement);
        log.info("发布公告: id={}, title={}", announcement.getId(), announcement.getTitle());

        // 通过WebSocket推送公告
        pushAnnouncementToUsers(announcement);
    }

    /**
     * 取消发布公告
     */
    @Transactional
    public void cancelAnnouncement(Long id) {
        Optional<Announcement> announcementOpt = announcementRepository.findById(id);
        if (announcementOpt.isEmpty()) {
            throw new RuntimeException("公告不存在: id=" + id);
        }

        Announcement announcement = announcementOpt.get();
        announcement.setStatus(Announcement.PublishStatus.CANCELLED);
        announcement.setUpdatedAt(LocalDateTime.now());

        announcementRepository.save(announcement);
        log.info("取消发布公告: id={}, title={}", announcement.getId(), announcement.getTitle());
    }

    /**
     * 删除公告
     */
    @Transactional
    public void deleteAnnouncement(Long id) {
        announcementRepository.deleteById(id);
        log.info("删除公告: id={}", id);
    }

    /**
     * 获取公告详情
     */
    public Optional<Announcement> getAnnouncementById(Long id) {
        return announcementRepository.findById(id);
    }

    /**
     * 获取公告详情并增加阅读次数
     */
    @Transactional
    public Optional<Announcement> getAnnouncementByIdAndIncrementReadCount(Long id) {
        Optional<Announcement> announcementOpt = announcementRepository.findById(id);
        if (announcementOpt.isPresent()) {
            announcementRepository.incrementReadCount(id);
        }
        return announcementOpt;
    }

    /**
     * 获取所有已发布的公告
     */
    public List<Announcement> getPublishedAnnouncements() {
        return announcementRepository.findByStatusOrderByCreatedAtDesc(Announcement.PublishStatus.PUBLISHED);
    }

    /**
     * 分页获取已发布的公告
     */
    public Page<Announcement> getPublishedAnnouncements(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return announcementRepository.findByStatusOrderByCreatedAtDesc(Announcement.PublishStatus.PUBLISHED, pageable);
    }

    /**
     * 根据目标类型获取公告
     */
    public List<Announcement> getAnnouncementsByTargetType(Announcement.TargetType targetType) {
        return announcementRepository.findByStatusAndTargetType(Announcement.PublishStatus.PUBLISHED, targetType);
    }

    /**
     * 分页根据目标类型获取公告
     */
    public Page<Announcement> getAnnouncementsByTargetType(Announcement.TargetType targetType, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return announcementRepository.findByStatusAndTargetType(Announcement.PublishStatus.PUBLISHED, targetType, pageable);
    }

    /**
     * 获取有效的公告
     */
    public List<Announcement> getValidAnnouncements() {
        return announcementRepository.findValidAnnouncements(LocalDateTime.now());
    }

    /**
     * 根据目标类型获取有效的公告
     */
    public List<Announcement> getValidAnnouncementsByTargetType(Announcement.TargetType targetType) {
        return announcementRepository.findValidAnnouncementsByTargetType(targetType, LocalDateTime.now());
    }

    /**
     * 获取置顶公告
     */
    public List<Announcement> getPinnedAnnouncements() {
        return announcementRepository.findPinnedAnnouncements(LocalDateTime.now());
    }

    /**
     * 搜索公告
     */
    public List<Announcement> searchAnnouncements(String keyword) {
        return announcementRepository.searchAnnouncements(keyword);
    }

    /**
     * 分页搜索公告
     */
    public Page<Announcement> searchAnnouncements(String keyword, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return announcementRepository.searchAnnouncements(keyword, pageable);
    }

    /**
     * 推送公告给用户
     */
    private void pushAnnouncementToUsers(Announcement announcement) {
        String targetType = announcement.getTargetType().name().toLowerCase();
        webSocketService.sendAnnouncement(
            announcement.getTitle(),
            announcement.getContent(),
            targetType
        );
        log.info("推送公告给用户: id={}, targetType={}", announcement.getId(), targetType);
    }

    /**
     * 定时任务：发布计划公告
     */
    @Scheduled(fixedRate = 60000) // 每分钟执行一次
    @Transactional
    public void publishScheduledAnnouncements() {
        int count = announcementRepository.publishScheduledAnnouncements(LocalDateTime.now());
        if (count > 0) {
            log.info("自动发布计划公告: count={}", count);
            
            // 获取刚发布的公告并推送
            List<Announcement> justPublished = announcementRepository.findScheduledAnnouncementsToPublish(LocalDateTime.now());
            for (Announcement announcement : justPublished) {
                pushAnnouncementToUsers(announcement);
            }
        }
    }

    /**
     * 定时任务：更新过期公告状态
     */
    @Scheduled(fixedRate = 300000) // 每5分钟执行一次
    @Transactional
    public void updateExpiredAnnouncements() {
        int count = announcementRepository.updateExpiredAnnouncements(LocalDateTime.now());
        if (count > 0) {
            log.info("更新过期公告状态: count={}", count);
        }
    }

    /**
     * 获取公告统计信息
     */
    public java.util.Map<String, Object> getAnnouncementStatistics() {
        List<Object[]> statusCounts = announcementRepository.countByStatus();
        List<Object[]> typeCounts = announcementRepository.countByType();
        
        java.util.Map<String, Object> statistics = new java.util.HashMap<>();
        statistics.put("statusCounts", statusCounts);
        statistics.put("typeCounts", typeCounts);
        
        return statistics;
    }
}
